#include "rdpserver.h"

std::vector<std::unique_ptr<rdpsession>> sessions;

std::filesystem::path RdpServer::m_tlsCertificate;
std::filesystem::path RdpServer::m_tlsCertificateKey;
/**
 * Called when a new client connects.
 * @param instance
 * @param client
 */
BOOL peer_accepted(freerdp_listener* instance, freerdp_peer* client)
{
	// HANDLE hThread;
	// WINPR_UNUSED(instance);

	// if (!(hThread = CreateThread(NULL, 0, peer_mainloop, (void*)client, 0, NULL)))
	// 	return FALSE;

	// CloseHandle(hThread);

	auto session= std::make_unique<rdpsession>();
	session->setclientPtr(client);
	session->settlsCertificate(RdpServer::tlsCertificate());
	session->settlsCertificateKey(RdpServer::tlsCertificateKey());
	session->initSettings();
	session->start();
	sessions.push_back(std::move(session));

	return TRUE;
}


RdpServer::RdpServer(QObject *parent):QObject(parent)
{
    initialize();
}
RdpServer::~RdpServer()
{
    destroy();
}
int RdpServer::initialize()
{
    WTSRegisterWtsApiFunctionTable(FreeRDP_InitWtsApi());
	winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT);
	m_instance = freerdp_listener_new();
    
    

	if (!m_instance)
    {
        qCritical()<<"Failed to create listener instance";
		return -1;
    }
	m_instance->PeerAccepted = peer_accepted;

	if (WSAStartup(MAKEWORD(2, 2), &m_wsaData) != 0)
	{
        qCritical()<<"Failed to initialize Winsock";
		freerdp_listener_free(m_instance);
		return -1;
	}

	/* Open the server socket and start listening. */
	sprintf_s(m_name, sizeof(m_name), "tfreerdp-server.%ld", m_port);
	m_file = GetKnownSubPath(KNOWN_PATH_TEMP, m_name);

	if (!m_file)
	{
        qCritical()<<"Failed to create temp file";
		freerdp_listener_free(m_instance);
		WSACleanup();
		return -1;
	}
    return 0;

}

 int RdpServer::destroy()
 {
    free(m_file);
	freerdp_listener_free(m_instance);
	WSACleanup();
    return 0;
 }


int RdpServer::start()
{
    if ((localOnly() || m_instance->Open(m_instance, NULL, port())) && m_instance->OpenLocal(m_instance, m_file))
	{
        qDebug()<<"server the listener has run";
		/* Entering the server main loop. In a real server the listener can be run in its own
		 * thread. */
		server_mainloop();
	}
}

void RdpServer::server_mainloop()
{
	HANDLE handles[32];
	DWORD count;
	DWORD status;

	if (m_instance)
	{
		while (1)
		{
			count = m_instance->GetEventHandles(m_instance, handles, 32);

			if (0 == count)
			{
				WLog_ERR(TAG, "Failed to get FreeRDP event handles");
				break;
			}

			status = WaitForMultipleObjects(count, handles, FALSE, INFINITE);

			if (WAIT_FAILED == status)
			{
				WLog_ERR(TAG, "select failed");
				break;
			}

			if (m_instance->CheckFileDescriptor(m_instance) != TRUE)
			{
				WLog_ERR(TAG, "Failed to check FreeRDP file descriptor");
				break;
			}
		}

		m_instance->Close(m_instance);
	}
	else
	{
		WLog_ERR(TAG, "FFreeRDP listener instance is NULL!");		
	}
}

int RdpServer::stop()
{

}

quint16 RdpServer::port() const
{
    return m_port;
}

void RdpServer::setPort(quint16 newPort)
{
    m_port = newPort;
}
bool RdpServer::localOnly() const
{
    return m_localOnly;
}
 void RdpServer::setLocalOnly(bool newLocalOnly)
 {
    m_localOnly = newLocalOnly;
 }
 
std::filesystem::path RdpServer::tlsCertificate() 
 {
	return m_tlsCertificate;
 }
void RdpServer::setTlsCertificate(const std::filesystem::path &newTlsCertificate)
 {
    m_tlsCertificate = newTlsCertificate;
 }
std::filesystem::path RdpServer::tlsCertificateKey() 
{
	return m_tlsCertificateKey;
}
void RdpServer::setTlsCertificateKey(const std::filesystem::path &newTlsCertificateKey)
{
    m_tlsCertificateKey = newTlsCertificateKey;
}
freerdp_listener* RdpServer::instance() const
{
	return m_instance;
}